package problem.eightqueue;

import java.util.Arrays;
import java.util.function.Consumer;

public class EightQueue {
    int sideLength;

    public EightQueue(int sideLength) {
        this.sideLength = sideLength;
    }

    public void find(Consumer<int[]> onFind) {
        int toUpdateRow = 0;
        boolean[] columnUsedStates = new boolean[sideLength];
        int[] board = new int[sideLength];
        Arrays.fill(board, -1);
        find(toUpdateRow, columnUsedStates, board, onFind);
    }

    private void find(int toUpdateRow, boolean[] columnUsedStates, int[] board, Consumer<int[]> onFind) {
        if (toUpdateRow == sideLength) {
            onFind.accept(board);
        } else {
            for (int columnIndex = 0; columnIndex < sideLength; columnIndex++) {
                if (!columnUsedStates[columnIndex]) {
                    if (trySetPosition(toUpdateRow, columnIndex, board)) {
                        columnUsedStates[columnIndex] = true;
                        board[toUpdateRow] = columnIndex;
                        find(toUpdateRow + 1, columnUsedStates, board, onFind);
                        board[toUpdateRow] = -1;
                        columnUsedStates[columnIndex] = false;
                    }
                }
            }
        }
    }

    private boolean trySetPosition(int toVisitRow, int position, int[] border) {
        for (int i = 0; i < toVisitRow; i++) {
            boolean state1 = border[toVisitRow] == position;
            boolean state2 = toVisitRow - position == i - border[i];
            boolean state3 = toVisitRow + position == i + border[i];
            if (state1 || state2 || state3) {
                return false;
            }
        }
        return true;
    }
}
